import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:ui';
import 'package:eip55/eip55.dart';
import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hex/hex.dart';
import 'package:http/http.dart' as http;
import 'package:wallet_sdk/wallet.dart';
import 'package:lib_database/lib_database.dart';

class Utils {
  static String checkSumEthereumAddress(String address) {
    return toChecksumAddress(address);
  }

  // static String getCurrentWalletMd5Key({Wallet? wallet}) {
  //   wallet ??= NavKey.navKey.currentContext!.read<WalletInfoNotifier>().wallet!;
  //   return wallet.getMd5Key();
  // }

  static Future<String> uploadFile(String url, String filePath) async {
    var request = http.MultipartRequest('POST', Uri.parse(url));
    File file;
    if (Platform.isAndroid) {
      file = File.fromUri(Uri.parse('file://$filePath'));
    } else {
      file = File(filePath);
    }
    var bytes = await file.readAsBytes();

    request.files.add(http.MultipartFile.fromBytes('file', bytes, filename: 'audio.wav'));

    var response = await request.send();
    if (response.statusCode == 200) {
      String responseStr = await response.stream.bytesToString();
      // Config.logger.d('uploadFile:$responseStr');
      Map<String, dynamic> result = json.decode(responseStr);
      return (result['data'] as Map<String, dynamic>)['fullurl'];
    }
    return '';
  }

  static String formatDateTime(int timestamp, {bool short = false, bool wrapLine = false}) {
    try {
      if (timestamp.toString().length < 13) {
        timestamp = timestamp * 1000;
      }
      var time = DateTime.fromMillisecondsSinceEpoch(timestamp);
      if (short) {
        return '${time.month.toString().padLeft(2, '0')}-'
            '${time.day.toString().padLeft(2, '0')} '
            '${time.hour.toString().padLeft(2, '0')}:'
            '${time.minute.toString().padLeft(2, '0')}';
      }
      return '${time.year}-'
          '${time.month.toString().padLeft(2, '0')}-'
          '${time.day.toString().padLeft(2, '0')}${wrapLine ? '\n' : ' '}'
          '${time.hour.toString().padLeft(2, '0')}:'
          '${time.minute.toString().padLeft(2, '0')}:'
          '${time.second.toString().padLeft(2, '0')}';
    } catch (e) {
      return '-';
    }
  }

  static String ensureRemoveHexPrefix(String hexData) {
    return hexData.startsWith('0x') ? hexData.substring(2) : hexData;
  }

  // static bool isCurrentLanguageZH({BuildContext? context}) {
  //   return (context ?? NavKey.navKey.currentState!.context)
  //       .locale
  //       .languageCode ==
  //       'zh';
  // }

  static void formatTokenBalancePriceValueFromServer(Token token, TokenType type) {
    try {
      token.balance = Utils.formatStringBalance(token.balance,
          fractionDigits: type == TokenType.token721 || type == TokenType.token1155 ? 0 : Config.balanceFixedNum,
          trimDecimalZero: true);

      token.priceusd = Utils.formatStringBalance(token.priceusd, fractionDigits: Config.balanceFixedNumUsingFiat);

      token.valueusd = Utils.formatStringBalance(token.valueusd, fractionDigits: Config.balanceFixedNumUsingFiat);

      if (null != token.totalSupply && token.totalSupply!.isNotEmpty) {
        token.totalSupply =
            Utils.formatStringBalance(token.totalSupply, fractionDigits: Config.balanceFixedNumUsingFiat);
      }
    } catch (e) {
      Config.logger.e(e);
    }
  }

  static String convertTronAddressFromBase58ToHex(String tronAddress) {
    return HEX.encode(Base58CheckCodec.bitcoin().decode(tronAddress).payload);
  }

  static String convertEthereumAddressFromHexToBase58(String ethereumAddress) {
    if (ethereumAddress.length == 42 && (ethereumAddress.startsWith('0x') || ethereumAddress.startsWith('41'))) {
      ethereumAddress = ethereumAddress.substring(2);
    }
    return Base58CheckCodec.bitcoin().encode(Base58CheckPayload(0x41, HEX.decode(ethereumAddress)));
  }

  // static bool isCurrentWatchWallet(BuildContext context,
  //     {bool showError = true}) {
  //   bool isWatch = context.read<WalletInfoNotifier>().isWatchWallet();
  //   if (isWatch && showError) {
  //     // EasyLoading.showError(
  //     //     LocaleKeys.guanchaqianbaobunnegjinxingcecaozuo.tr());
  //     print(LocaleKeys.guanchaqianbaobunnegjinxingcecaozuo.tr());
  //   }
  //   return isWatch;
  // }

  static bool isUrl(String url) {
    final RegExp urlRegex = RegExp(
      r"^(https?://)?[\da-z.-]+(\.[a-z.]{2,6})(:\d{1,5})?([/?#][\w-./?%&=]*)?$",
      caseSensitive: false,
      multiLine: false,
    );
    // 检查输入的字符串是否符合HTTP和HTTPS协议以及端口号的格式
    return urlRegex.hasMatch(url);
  }

  // 判断一个字符串是否是Tron地址
  static bool isTronAddress(String address) {
    RegExp regExp = RegExp(r"^T[1-9A-HJ-NP-Za-km-z]{33}$");
    return regExp.hasMatch(address);
  }

  // 判断一个字符串是否是以太坊地址
  static bool isEthereumAddress(String address) {
    RegExp regExp = RegExp(r"^0x[0-9a-fA-F]{40}$");
    return regExp.hasMatch(address);
  }

  // 判断一个字符串是否是以太坊地址
  static bool isSolana(String address) {
    RegExp regExp = RegExp(r"^[1-9A-HJ-NP-Za-km-z]{32,44}$");
    return regExp.hasMatch(address);
  }

  static String formatAddress(String address, {int len = 6}) {
    if (address.length < len) return address;
    return '${address.substring(0, len)}...${address.substring(address.length - len)}';
  }

  static bool isMnemonic(String key) {
    if (key.contains(' ')) {
      List<String> wordsList = key.split(' ');
      if (wordsList.length == 12 || wordsList.length == 24) {
        for (var s in wordsList) {
          if (s.isEmpty) {
            return false;
          }
        }
        return true;
      }
    }
    return false;
  }

  static const String _pkReg = "^(?:0x)?[0-9a-fA-F]{64}\$";
  static const String _btcWifPkReg = "^[5KL][1-9A-HJ-NP-Za-km-z]{51}\$";

  static bool isPrivateKey(String key) {
    return null != RegExp(_pkReg).firstMatch(key);
  }

  static bool isBtcWifPrivateKey(String key) {
    return null != RegExp(_btcWifPkReg).firstMatch(key);
  }

  static double screenWidth() {
    return window.physicalSize.width;
  }

  static double screenHeight() {
    return window.physicalSize.height;
  }

  static double dp2px(double dp) {
    return dp * window.devicePixelRatio;
  }

  static double px2dp(double px) {
    return px / window.devicePixelRatio;
  }

  static Color getRandomColor({int r = 255, int g = 255, int b = 255, a = 255}) {
    if (r == 0 || g == 0 || b == 0) return Colors.black;
    if (a == 0) return Colors.white;
    return Color.fromARGB(
      a,
      r != 255 ? r : Random.secure().nextInt(r),
      g != 255 ? g : Random.secure().nextInt(g),
      b != 255 ? b : Random.secure().nextInt(b),
    );
  }

  // static String trimZero(String num) {
  //   return num.replaceAll(RegExp(r"0+?$"), "").replaceAll(RegExp(r"[.]$"), "");
  // }

  static String compressZero(String num) {
    if (num.startsWith("0.00") && num.length > 4) {
      int noZeroIndex = -1;
      for (int i = 4; i < num.length; i++) {
        if ("0" != num.substring(i, i + 1)) {
          noZeroIndex = i;
          break;
        }
      }
      if (noZeroIndex != -1) {
        return '0.{${noZeroIndex - 2}}${num.substring(noZeroIndex)}';
      }
    }
    return num;
  }

  static String compressNum(String num) {
    Decimal? dec = Decimal.tryParse(num);
    if (null == dec) {
      return num;
    }

    Decimal dec1k = Decimal.fromInt(1000);
    Decimal dec1m = Decimal.fromInt(1000000);
    Decimal dec1b = Decimal.parse('1000000000');

    if (dec.compareTo(dec1k) >= 0 && dec.compareTo(dec1m) < 0) {
      //1k - 1000k
      return '${formatDecimalBalance((dec / dec1k).toDecimal(), fractionDigits: 2, trimDecimalZero: true)}k';
    } else if (dec.compareTo(dec1m) >= 0 && dec.compareTo(dec1b) < 0) {
      //1m - 1000m
      return '${formatDecimalBalance((dec / dec1m).toDecimal(), fractionDigits: 2, trimDecimalZero: true)}m';
    } else if (dec.compareTo(dec1b) >= 0) {
      //1b ->
      return '${formatDecimalBalance((dec / dec1b).toDecimal(), fractionDigits: 2, trimDecimalZero: true)}b';
    } else {
      return formatStringBalance(num, fractionDigits: 2, trimDecimalZero: true);
    }
  }

  static String formatDoubleDownWithoutZero(double num, {int fractionDigits = 2}) {
    return formatStringBalance(num.toString(), fractionDigits: fractionDigits, trimDecimalZero: true);
  }

  // static String formatTokenBalance(String? balance) {
  //   return formatStringBalance(balance,
  //       fractionDigits: Config.balanceFixedNum, trimDecimalZero: true);
  // }

  static String formatStringBalance(String? balance, {int fractionDigits = 2, bool trimDecimalZero = false}) {
    if (null == balance || balance.isEmpty) {
      return fractionDigits == 0 ? '0' : '0.00';
    }
    try {
      String str = formatDecimalBalance(Decimal.parse(balance),
          fractionDigits: fractionDigits, trimDecimalZero: trimDecimalZero);
      if (int.tryParse(str) != null) {
        return str + '.00';
      } else {
        return str;
      }
    } catch (e) {
      // Config.logger.e(e);
      return '0.00';
    }
  }

  static String formatDecimalBalance(Decimal? balance, {int fractionDigits = 2, bool trimDecimalZero = false}) {
    if (null == balance) return fractionDigits == 0 ? '0' : '0.00';
    try {
      // double result = double.parse(balance.toStringAsFixed(fractionDigits));
      String result = balance.floor(scale: fractionDigits).toStringAsFixed(fractionDigits);
      if (trimDecimalZero) {
        return Decimal.parse(result).toString();
      }
      return result;
    } catch (e) {
      // Config.logger.e(e);
      return '0.00';
    }
  }

  static String formatDoubleBalance(double? balance, {int fractionDigits = 2, bool trimDecimalZero = false}) {
    return formatStringBalance(null == balance ? '0' : balance.toString(),
        fractionDigits: fractionDigits, trimDecimalZero: trimDecimalZero);
  }

  static bool isEmpty(String? data) {
    return null == data || data.isEmpty;
  }

  static bool isBase64(String? data) {
    try {
      base64.decode(data!);
      return true;
    } catch (e) {
      return false;
    }
  }

  static bool existEmpty(List<String?> data) {
    for (var d in data) {
      if (null == d || d.isEmpty) {
        return true;
      }
    }
    return false;
  }

  static bool isNotEmpty(String? data) {
    return !isEmpty(data);
  }

  static bool isZero(String? data) {
    if (null == data || data.isEmpty) {
      return true;
    } else {
      try {
        return double.parse(data) == 0;
      } catch (e) {
        // Config.logger.d('isZero: $e,data:$data');
        return false;
      }
    }
  }

  static Future showBottomSheetDialog(BuildContext context, Widget child, {bool canPop = false}) {
    return showModalBottomSheet(
        context: context,
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        enableDrag: false,
        useSafeArea: false,
        //如果为true，最底部颜色为半透明色
        builder: (context) {
          return WillPopScope(
              child: Container(
                margin: EdgeInsets.only(top: MediaQueryData.fromView(window).padding.top),
                child: child,
              ),
              onWillPop: () {
                return Future.value(canPop);
              });
        });
  }

  static Future showSheet<T>(BuildContext context, Widget body,
      {bool isDismissible = false,
      bool scrollControlled = false,
      Color bodyColor = Colors.white,
      EdgeInsets? bodyPadding,
      BorderRadius? borderRadius,
      bool canPop = false}) {
    const radius = Radius.circular(16);
    borderRadius ??= const BorderRadius.only(topLeft: radius, topRight: radius);
    bodyPadding ??= const EdgeInsets.all(20);
    return showModalBottomSheet(
        context: context,
        elevation: 0,
        isDismissible: isDismissible,
        backgroundColor: bodyColor,
        shape: RoundedRectangleBorder(borderRadius: borderRadius),
        barrierColor: Colors.black.withOpacity(0.25),
        // A处
        constraints:
            BoxConstraints(maxHeight: MediaQuery.of(context).size.height - MediaQuery.of(context).viewPadding.top),
        isScrollControlled: scrollControlled,
        builder: (ctx) => Padding(
              padding: EdgeInsets.only(
                left: bodyPadding!.left,
                top: bodyPadding.top,
                right: bodyPadding.right,
                // B处
                bottom: bodyPadding.bottom + MediaQuery.of(ctx).viewPadding.bottom,
              ),
              child: WillPopScope(
                  child: body,
                  onWillPop: () {
                    return Future.value(canPop);
                  }),
            ));
  }

  static bool copyText(String text, {bool showCopySuccessTip = true}) {
    Clipboard.setData(ClipboardData(text: text));
    if (showCopySuccessTip) {
      return true;
      // EasyLoading.showSuccess(LocaleKeys.fuzhichenggong.tr());
    }
    return false;
  }
}
